package com.yupi.springbootinit.statemachine.processor;

import com.yupi.springbootinit.statemachine.core.StateContext;
import com.yupi.springbootinit.statemachine.core.StateProcessor;
import com.yupi.springbootinit.statemachine.enums.ProcessSheetStateEnum;
import com.yupi.springbootinit.statemachine.enums.ProcessSheetEventEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 工艺单状态处理器
 * 处理工艺单状态转换的业务逻辑
 */
@Slf4j
@Component
public class ProcessSheetStateProcessor implements StateProcessor<ProcessSheetStateEnum, ProcessSheetEventEnum> {
    
    @Override
    public boolean beforeTransition(StateContext context) {
        log.info("工艺单状态转换前置处理: 实体[{}] {} -> {}", 
            context.getEntityId(),
            context.getCurrentState().getCode(),
            context.getTargetState().getCode());
        
        ProcessSheetStateEnum currentState = (ProcessSheetStateEnum) context.getCurrentState();
        ProcessSheetStateEnum targetState = (ProcessSheetStateEnum) context.getTargetState();
        
        switch (currentState) {
            case DRAFT:
                return handleDraftToPublished(context);
            case PUBLISHED:
                return handlePublishedToChanged(context);
            case CHANGED:
                return handleChangedToPublished(context);
            default:
                return true;
        }
    }
    
    @Override
    public void afterTransition(StateContext context) {
        log.info("工艺单状态转换后置处理: 实体[{}] 转换完成", context.getEntityId());
        
        ProcessSheetStateEnum targetState = (ProcessSheetStateEnum) context.getTargetState();
        
        // 根据目标状态执行相应的后置处理
        switch (targetState) {
            case PUBLISHED:
                handleAfterPublish(context);
                break;
            case CHANGED:
                handleAfterChange(context);
                break;
        }
        
        // 发送通知
        sendNotification(context);
    }
    
    @Override
    public void onTransitionError(StateContext context, Exception exception) {
        log.error("工艺单状态转换失败: 实体[{}] {} -> {}, 错误: {}", 
            context.getEntityId(),
            context.getCurrentState().getCode(),
            context.getTargetState().getCode(),
            exception.getMessage());
        
        // 记录错误并发送告警
        recordError(context, exception);
    }
    
    @Override
    public String getSupportedStateType() {
        return "PROCESS_SHEET";
    }
    
    /**
     * 处理草稿到已发布的转换
     */
    private boolean handleDraftToPublished(StateContext context) {
        Long processSheetId = context.getEntityId();
        log.debug("检查工艺单[{}]发布条件", processSheetId);
        
        // 检查工艺单是否完整
        if (!checkProcessSheetComplete(processSheetId)) {
            log.warn("工艺单[{}]信息不完整，不能发布", processSheetId);
            return false;
        }
        
        // 检查工序路线是否合理
        if (!validateProcessRoute(processSheetId)) {
            log.warn("工艺单[{}]工序路线不合理", processSheetId);
            return false;
        }
        
        // 检查检验要求是否完整
        if (!validateInspectionRequirements(processSheetId)) {
            log.warn("工艺单[{}]检验要求不完整", processSheetId);
            return false;
        }
        
        return true;
    }
    
    /**
     * 处理已发布到已变更的转换
     */
    private boolean handlePublishedToChanged(StateContext context) {
        Long processSheetId = context.getEntityId();
        log.debug("检查工艺单[{}]变更条件", processSheetId);
        
        // 检查是否有关联的生产订单正在执行
        if (hasActiveProductionOrders(processSheetId)) {
            log.warn("工艺单[{}]有正在执行的生产订单，不能变更", processSheetId);
            return false;
        }
        
        return true;
    }
    
    /**
     * 处理已变更到已发布的转换（重新发布）
     */
    private boolean handleChangedToPublished(StateContext context) {
        Long processSheetId = context.getEntityId();
        log.debug("检查工艺单[{}]重新发布条件", processSheetId);
        
        // 重新验证工艺单完整性
        return handleDraftToPublished(context);
    }
    
    /**
     * 工艺单发布后的处理
     */
    private void handleAfterPublish(StateContext context) {
        Long processSheetId = context.getEntityId();
        ProcessSheetStateEnum currentState = (ProcessSheetStateEnum) context.getCurrentState();
        
        if (currentState == ProcessSheetStateEnum.DRAFT) {
            // 首次发布
            handleFirstTimePublish(processSheetId);
        } else if (currentState == ProcessSheetStateEnum.CHANGED) {
            // 重新发布
            handleRepublish(processSheetId);
        }
        
        // 更新发布时间和发布人
        updatePublishInfo(processSheetId, context.getOperatorId(), context.getOperatorName());
        
        // 生成工序实例模板
        generateProcessInstanceTemplates(processSheetId);
        
        // 通知PMC创建生产排期
        notifyPMCForScheduling(processSheetId);
        
        log.info("工艺单[{}]已发布", processSheetId);
    }
    
    /**
     * 工艺单变更后的处理
     */
    private void handleAfterChange(StateContext context) {
        Long processSheetId = context.getEntityId();
        
        // 记录变更历史
        recordChangeHistory(processSheetId, context);
        
        // 通知相关部门工艺变更
        notifyProcessSheetChange(processSheetId);
        
        log.info("工艺单[{}]已标记为变更", processSheetId);
    }
    
    /**
     * 首次发布处理
     */
    private void handleFirstTimePublish(Long processSheetId) {
        // 生成工艺单版本号
        generateVersionNumber(processSheetId);
        
        // 创建工艺文件归档
        archiveProcessFiles(processSheetId);
        
        // 推送工序清单给品质部
        pushProcessListToQuality(processSheetId);
        
        log.info("工艺单[{}]首次发布完成", processSheetId);
    }
    
    /**
     * 重新发布处理
     */
    private void handleRepublish(Long processSheetId) {
        // 更新版本号
        updateVersionNumber(processSheetId);
        
        // 比较变更内容
        compareAndRecordChanges(processSheetId);
        
        // 通知PMC评估排期调整
        notifyPMCForScheduleAdjustment(processSheetId);
        
        log.info("工艺单[{}]重新发布完成", processSheetId);
    }
    
    /**
     * 发送通知
     */
    private void sendNotification(StateContext context) {
        ProcessSheetStateEnum targetState = (ProcessSheetStateEnum) context.getTargetState();
        Long processSheetId = context.getEntityId();
        
        switch (targetState) {
            case PUBLISHED:
                if (context.getCurrentState() == ProcessSheetStateEnum.DRAFT) {
                    log.info("通知PMC: 工艺单[{}]已发布，可创建生产排期", processSheetId);
                    log.info("通知品质部: 工艺单[{}]已发布，已推送工序清单", processSheetId);
                } else {
                    log.info("通知PMC: 工艺单[{}]已重新发布，请评估排期调整", processSheetId);
                }
                break;
            case CHANGED:
                log.info("通知相关部门: 工艺单[{}]已变更", processSheetId);
                break;
        }
    }
    
    // 以下为业务逻辑方法的简化实现
    
    private boolean checkProcessSheetComplete(Long processSheetId) {
        // 检查工艺单基本信息是否完整
        // - 机型、料粉信息
        // - 至少包含一道工序
        // - 工序顺序号、名称、技术要求
        log.debug("检查工艺单[{}]完整性", processSheetId);
        return true; // 简化实现
    }
    
    private boolean validateProcessRoute(Long processSheetId) {
        // 验证工序路线的合理性
        // - 工序顺序是否连续
        // - 外协工序标记是否正确
        // - 工序间的逻辑关系是否合理
        log.debug("验证工艺单[{}]工序路线", processSheetId);
        return true; // 简化实现
    }
    
    private boolean validateInspectionRequirements(Long processSheetId) {
        // 验证检验要求的完整性
        // - 需检工序是否设置了检验方式
        // - 检验标准是否明确
        // - 检验要点是否完整
        log.debug("验证工艺单[{}]检验要求", processSheetId);
        return true; // 简化实现
    }
    
    private boolean hasActiveProductionOrders(Long processSheetId) {
        // 检查是否有正在执行的生产订单使用此工艺单
        log.debug("检查工艺单[{}]关联的生产订单", processSheetId);
        return false; // 简化实现
    }
    
    private void updatePublishInfo(Long processSheetId, Long operatorId, String operatorName) {
        // 更新发布时间和发布人信息
        log.debug("更新工艺单[{}]发布信息，发布人: {}", processSheetId, operatorName);
    }
    
    private void generateProcessInstanceTemplates(Long processSheetId) {
        // 根据工艺单生成工序实例模板
        log.debug("为工艺单[{}]生成工序实例模板", processSheetId);
    }
    
    private void notifyPMCForScheduling(Long processSheetId) {
        // 通知PMC创建生产排期
        log.debug("通知PMC为工艺单[{}]创建生产排期", processSheetId);
    }
    
    private void recordChangeHistory(Long processSheetId, StateContext context) {
        // 记录变更历史
        log.debug("记录工艺单[{}]变更历史", processSheetId);
    }
    
    private void notifyProcessSheetChange(Long processSheetId) {
        // 通知相关部门工艺变更
        log.debug("通知相关部门工艺单[{}]变更", processSheetId);
    }
    
    private void generateVersionNumber(Long processSheetId) {
        // 生成版本号
        log.debug("为工艺单[{}]生成版本号", processSheetId);
    }
    
    private void archiveProcessFiles(Long processSheetId) {
        // 归档工艺文件
        log.debug("归档工艺单[{}]相关文件", processSheetId);
    }
    
    private void pushProcessListToQuality(Long processSheetId) {
        // 推送工序清单给品质部
        log.debug("推送工艺单[{}]工序清单给品质部", processSheetId);
    }
    
    private void updateVersionNumber(Long processSheetId) {
        // 更新版本号
        log.debug("更新工艺单[{}]版本号", processSheetId);
    }
    
    private void compareAndRecordChanges(Long processSheetId) {
        // 比较并记录变更内容
        log.debug("比较并记录工艺单[{}]变更内容", processSheetId);
    }
    
    private void notifyPMCForScheduleAdjustment(Long processSheetId) {
        // 通知PMC评估排期调整
        log.debug("通知PMC评估工艺单[{}]排期调整", processSheetId);
    }
    
    private void recordError(StateContext context, Exception exception) {
        // 记录错误信息
        log.error("工艺单[{}]状态转换错误: {}", context.getEntityId(), exception.getMessage());
    }
}